#'
#' @TODO 复杂情况KM曲线
#' @title  复杂情况KM曲线
#' @description 在得分的不同的分组情况下绘制KM曲线，并输出p值，保存分组文件以及图片.
#' @details 详见参数说明
#' @param Input *data.frame*，得分信息
#' @param surtime_unit 生存信息时间scale，年月日，对应365,12,1
#' @param time_col   `Input`中的的时间信息所在列
#' @param status_col *character*, 生存状态信息所在列
#' @param score_col *character*, 得分所在列列名
#' @param BestCut  *Boolean value*，是否使用最优cutoff作为切割点进行分析
#' @param NormalCut *Boolean value*，是否使用中位数切割点进行分析
#' @param TertileCut *Boolean value*，是否使用top mid bottom三分组进行KM分析，进行两种分析，三组间分析一次；top与bottom分析一次
#' @param QuartileCut *Boolean value*，四分组C1 C2 C3 C4进行KM分析，C1为高得分组。三种情况：
#'   - C1 C2 C3 C4 四分组间绘制KM曲线计算p值
#'   - C1 C2/C3/C4 二分组进行绘制KM曲线
#'   - C1 C4 两组样本绘制KM曲线
#' @param CutOffManual *numeric value*,是否手动指定一个具体数值作为cutoff，划分样本为高低两组
#' @param SaveFile *Boolean value*，是否保存文件
#' @param od *character*，文件保存路径
#'
#' @return *list*，里面包含每种情况下的分析结果。**其中`KM_p_Infor`为各KM曲线的p值信息**
#' @usage
#' file_dir <- '/Pub/Users/wangyk/project/tmp/mimandaB/reverse_A_B/output/KM_ROC_curve_GSE31312_OS/table_GSE31312_OS_Input.txt'
#' data <- data.table::fread(file_dir) %>%
#' as.data.frame()
#' source('/Pub/Users/wangyk/Project_wangyk/Codelib_YK/some_scr/complex_KM.R')
#' @usage
#' resTmp <- ComplexKM_v2(Input = NULL, surtime_unit = c(1, 12, 365),
#'                         time_col = 'time', status_col = 'status', score_col = 'riskscore',
#'                         BestCut = T, NormalCut = T, TertileCut = T, QuartileCut = T, CutOffManual = NULL,
#'                         GroupManul = NULL, legend = 'top',
#'                         SaveFile = T, od = './', w = 5, h = 5)
#' @export
#' @author *WYK*
#'
ComplexKM <- function(
    Input = NULL, surtime_unit = c(1, 12, 365), time_col = "time",
    status_col = "status", score_col = "riskscore", BestCut = F, NormalCut = T, TertileCut = F,
    QuartileCut = F, CutOffManual = NULL, SaveFile = T, od = "./", w = 5, h = 5, type = "OS") {
  library(tidyverse)
  library(survival)
  library(survminer)

  walk(colnames(Input), function(x) {
    if ("time" == x & "time" != time_col) {
      Input <- Input %>%
        dplyr::rename(time_raw = "time")
    }
    if ("status" == x & "status" != status_col) {
      Input <- Input %>%
        dplyr::rename(status_raw = "status")
    }
    if ("Score" == x & "Score" != score_col) {
      Input <- Input %>%
        dplyr::rename(Score_raw = "Score")
    }
  })

  Input <- Input %>%
    dplyr::rename(time = all_of(time_col), status = all_of(status_col), Score = all_of(score_col)) %>%
    mutate(time = as.numeric(time), status = as.numeric(status)) %>%
    filter(time > 0) %>%
    filter(status != "NA" & status != "")

  two_class_KM <- function(Input) {
    if (unique(Input$Group) %>%
      length() == 2) {
      if (all(unique(Input$Group) %in% c("Top", "Bottom"))) {
        legend_chr <- factor(c("Bottom", "Top"), levels = c("Top", "Bottom"))
        # legend_chr <- c('Bottom', 'Top')
      } else if (all(unique(Input$Group) %in% c("C1", "C2/C3/C4"))) {
        legend_chr <- c("C1", "C2/C3/C4")
      } else if (all(unique(Input$Group) %in% c("C4", "C1/C2/C3"))) {
        legend_chr <- c("C1/C2/C3", "C4")
      } else if (all(unique(Input$Group) %in% c("C1", "C4"))) {
        legend_chr <- c("C1", "C4")
      } else if (all(unique(Input$Group) %in% c("High", "Low"))) {
        legend_chr <- c("High", "Low")
      }

      if (length(unique(Input$Group)) != 1) {
        coxtmp <- summary(coxph(Surv(time, status) ~ HR_group, data = Input))

        HR <- coxtmp$coefficients[2]
        logrank_pvalue <- coxtmp$sctest["pvalue"]
        lower_.95 <- coxtmp$conf.int[, "lower .95"]
        upper_.95 <- coxtmp$conf.int[, "upper .95"]
        C <- coxtmp$concordance[1]

        p_chara <- paste0(
          ifelse(logrank_pvalue < 0.001, "P < 0.001", paste0(
            "P = ",
            round(logrank_pvalue, 3)
          )), "\n", "HR = ", round(HR, 2), "\n95% CI = ",
          round(lower_.95, 2), " - ", round(upper_.95, 2), "\nC-index = ",
          round(C, 2)
        )

        if (surtime_unit == 12) {
          chara_xlab <- "Time (Months)"
        } else if (surtime_unit == 365) {
          chara_xlab <- "Time (Days)"
        } else if (surtime_unit == 1) {
          chara_xlab <- "Time (Years)"
        } else {
          chara_xlab <- "Time"
        }

        fit <- surv_fit(Surv(time, status) ~ Group, data = Input)
        KM <- ggsurvplot(fit,
          data = Input, surv.median.line = "hv", legend.title = "Score",
          legend.labs = legend_chr, palette = "Set1", ggtheme = theme_pubr(),
          pval = p_chara, pval.size = 4.5, xlab = chara_xlab, tables.height = 0.28,
          risk.table = T
        )

        res <- list()

        p_auc_res <- tibble(KM_p = logrank_pvalue, HR = round(HR, 2))

        p <- ggarrange(
          KM$plot + labs(x = "") +
            theme(plot.margin = unit(c(0.2, 0.2, -0.23, 0.2), "cm")),
          KM$table +
            theme(plot.margin = unit(c(-0.23, 0.2, 0.2, 0.2), "cm")),
          ncol = 1, align = "v", heights = c(0.75, 0.3)
        )
        # print(cowplot::plot_grid(p, res[[2]], rel_widths = c(0.95,
        # 1.05), scale = c(1, .97)))

        res[[1]] <- p
        res[[2]] <- p_auc_res
      } else {
        res <- list()
      }
    }

    return(res)
  }

  more_class_KM <- function(Input) {
    if (unique(Input$Group) %>%
      length() != 2) {
      if (all(unique(Input$Group) %in% c("Top", "Mid", "Bottom"))) {
        # legend_chr <- c('Bottom', 'Mid', 'Top')
        legend_chr <- factor(c("Bottom", "Mid", "Top"), levels = c(
          "Top",
          "Mid", "Bottom"
        ))
      }
      if (all(unique(Input$Group) %in% c("C1", "C2", "C3", "C4"))) {
        legend_chr <- c("C1", "C2", "C3", "C4")
      }

      if (length(unique(Input$Group)) != 1) {
        if (surtime_unit == 12) {
          chara_xlab <- "Time (Months)"
        } else if (surtime_unit == 365) {
          chara_xlab <- "Time (Days)"
        } else if (surtime_unit == 1) {
          chara_xlab <- "Time (Years)"
        } else {
          chara_xlab <- "Time"
        }

        fit <- surv_fit(Surv(time, status) ~ Group, data = Input)
        KM <- ggsurvplot(fit,
          data = Input, surv.median.line = "hv", legend.title = "Score",
          legend.labs = legend_chr, palette = "Set1", ggtheme = theme_pubr(),
          pval = T, pval.method = T, pval.size = 4.5, xlab = chara_xlab,
          tables.height = 0.28, risk.table = T
        )

        res <- list()

        p_auc_res <- tibble(surv_pvalue(fit, data = Input))
        p_auc_res <- p_auc_res %>%
          dplyr::select(-variable, -method, -pval.txt) %>%
          dplyr::rename(KM_p = pval)

        p <- cowplot::plot_grid(
          KM$plot + labs(x = "") + theme(plot.margin = unit(c(
            0.2,
            0.2, -0.15, 0.2
          ), "cm")), KM$table + theme(plot.margin = unit(c(
            -0.15,
            0.2, 0.2, 0.2
          ), "cm"), axis.text.x = element_text(size = 7)),
          ncol = 1,
          align = "v", rel_heights = c(0.7, 0.3)
        )

        # print(cowplot::plot_grid(p, res[[2]], rel_widths = c(0.95,
        # 1.05), scale = c(1, .97)))
        res[[1]] <- p
        res[[2]] <- p_auc_res
      } else {
        res <- list()
      }
    }

    return(res)
  }

  if (nrow(Input) > 10) {
    if (BestCut) {
      sur.cut <- surv_cutpoint(
        data = Input, time = "time", event = "status",
        variables = "Score", minprop = 0.1
      )
      cut <- summary(sur.cut)$cutpoint

      Input_BestCut <- Input %>%
        mutate(HR_group = ifelse(Score > cut, 1, 0)) %>%
        mutate(Group = ifelse(Score > cut, "High", "Low"))

      BestCut_KM <- two_class_KM(Input_BestCut)
      names(BestCut_KM) <- c("KM_BestCut", "KM_BestCut_Infor")
      BestCut_KM[["BestCut_GroupInfor"]] <- Input_BestCut
    } else {
      BestCut_KM <- list()
    }

    if (NormalCut) {
      Input_normal <- Input %>%
        mutate(HR_group = ifelse(Score > median(Score), 1, 0)) %>%
        mutate(Group = ifelse(Score > median(Score), "High", "Low"))

      NormalCut_KM <- two_class_KM(Input_normal)
      names(NormalCut_KM) <- c("KM_NormalCut", "KM_NormalCut_Infor")
      NormalCut_KM[["NormalCut_GroupInfor"]] <- Input_normal
    } else {
      NormalCut_KM <- list()
    }

    if (TertileCut) {
      Input_TertileCut <- Input %>%
        mutate(Group = as.character(cut(Score, breaks = quantile(
          x = Score,
          probs = seq(0, 1, 1 / 3)
        ), labels = c("Bottom", "Mid", "Top"), include.lowest = TRUE)))

      if (Input_TertileCut$Group %>%
        unique() %>%
        length() == 3) {
        Input_TertileCut_two <- Input_TertileCut %>%
          filter(Group %in% c("Top", "Bottom")) %>%
          mutate(HR_group = ifelse(Group == "Top", 1, 0))

        TertileCut_KM <- two_class_KM(Input_TertileCut_two)
        names(TertileCut_KM) <- c("KM_twoClass_in_TertileCut", "KM_twoClass_in_TertileCut_Infor")
        TertileCut_KM[["TertileCut_GroupInfor"]] <- Input_TertileCut


        TertileCut_Three_class_KM <- more_class_KM(Input_TertileCut)


        TertileCut_KM[["KM_threeClass_in_TertileCut"]] <- TertileCut_Three_class_KM[[1]]
        TertileCut_KM[["KM_threeClass_in_TertileCut_Infor"]] <- TertileCut_Three_class_KM[[2]]
      } else {
        TertileCut_KM <- list()
      }
    } else {
      TertileCut_KM <- list()
    }

    if (QuartileCut) {
      Input_QuartileCut <- Input %>%
        mutate(Group = as.character(cut(Score, breaks = quantile(
          x = Score,
          probs = seq(0, 1, 1 / 4)
        ), labels = c("C4", "C3", "C2", "C1"), include.lowest = TRUE)))

      if (unique(Input_QuartileCut$Group) %>%
        length() == 4) {
        Input_QuartileCut_C1C4 <- Input_QuartileCut %>%
          filter(Group %in% c("C1", "C4")) %>%
          mutate(HR_group = ifelse(Group == "C1", 1, 0))

        # rm(list = 'QuartileCut_KM')

        QuartileCut_KM <- two_class_KM(Input_QuartileCut_C1C4)
        names(QuartileCut_KM) <- c("KM_C1C4_in_QuartileCut", "KM_C1C4_in_QuartileCut_Infor")
        QuartileCut_KM[["QuartileCut_GroupInfor"]] <- Input_QuartileCut

        # names(QuartileCut_KM) 1 vs 234
        Input_QuartileCut_C1C234 <- Input_QuartileCut %>%
          mutate(HR_group = ifelse(Group == "C1", 1, 0)) %>%
          mutate(Group = case_when(Group %in% "C1" ~ "C1", Group %in% c(
            "C2",
            "C3", "C4"
          ) ~ "C2/C3/C4"))

        QuartileCut_KM_C1C234 <- two_class_KM(Input_QuartileCut_C1C234)
        QuartileCut_KM[["KM_C1C234_in_QuartileCut"]] <- QuartileCut_KM_C1C234[[1]]
        QuartileCut_KM[["KM_C1C234_in_QuartileCut_Infor"]] <- QuartileCut_KM_C1C234[[2]]

        # 123 vs 4
        Input_QuartileCut_C123C4 <- Input_QuartileCut %>%
          mutate(Group = case_when(Group %in% "C4" ~ "C4", Group %in% c(
            "C1",
            "C2", "C3"
          ) ~ "C1/C2/C3")) %>%
          mutate(HR_group = ifelse(Group == "C1/C2/C3", 1, 0))

        QuartileCut_KM_C123C4 <- two_class_KM(Input_QuartileCut_C123C4)
        QuartileCut_KM[["KM_C123C4_in_QuartileCut"]] <- QuartileCut_KM_C123C4[[1]]
        QuartileCut_KM[["KM_C123C4_in_QuartileCut_Infor"]] <- QuartileCut_KM_C123C4[[2]]

        # 1 vs 2 vs 3 vs 4
        Input_QuartileCut_C1234 <- more_class_KM(Input_QuartileCut)
        QuartileCut_KM[["KM_C1234_in_QuartileCut"]] <- Input_QuartileCut_C1234[[1]]
        QuartileCut_KM[["KM_C1234_in_QuartileCut_Infor"]] <- Input_QuartileCut_C1234[[2]]
      } else {
        QuartileCut_KM <- list()
      }
    } else {
      QuartileCut_KM <- list()
    }

    if (!is.null(CutOffManual)) {
      Input_CutOffManual <- Input %>%
        mutate(HR_group = ifelse(Score > CutOffManual, 1, 0)) %>%
        mutate(Group = ifelse(Score > CutOffManual, "High", "Low"))

      CutOffManual_KM <- two_class_KM(Input_CutOffManual)
      names(CutOffManual_KM) <- c("KM_CutOffManual", "KM_CutOffManual_Infor")
      CutOffManual_KM[["CutOffManual_GroupInfor"]] <- Input_CutOffManual
    } else {
      CutOffManual_KM <- list()
    }

    res <- list(BestCut_KM, NormalCut_KM, TertileCut_KM, QuartileCut_KM, CutOffManual_KM)
    names(res) <- c(
      "BestCut_KM", "NormalCut_KM", "TertileCut_KM", "QuartileCut_KM",
      "CutOffManual_KM"
    )

    num_of_single_list <- map_int(names(res), ~ length(res[[.x]]))

    res_index <- which(num_of_single_list != 0)

    if (SaveFile) {
      if (!dir.exists(od)) {
        dir.create(od, recursive = T)
      }

      walk(res_index, function(x) {
        walk(names(res[[x]]), function(y) {
          single_file <- res[[x]][[y]]
          if (any(str_detect(class(single_file), "gg"))) {
            ggsave(
              plot = single_file, file = file.path(od, str_glue("Figure_{y}_KM_plot.pdf")),
              width = w, height = h
            )
          }
          if (any(str_detect(class(single_file), "data.frame"))) {
            write_tsv(x = single_file, file = file.path(od, str_glue("Table_{y}.tsv")))
          }
        })
      })
    }

    KM_p_Infor <- map_dfr(res_index, function(x) {
      p_infor <- map_dfr(names(res[[x]]), function(y) {
        single_file <- res[[x]][[y]]
        if (any(str_detect(class(single_file), "data.frame"))) {
          if (dim(single_file)[1] == 1) {
            single_file[["ClassType"]] <- y
            return(single_file)
          }
        }
      })
    })

    res <- res[res_index]
    res[["KM_p_Infor"]] <- KM_p_Infor
  } else {
    message("N.of sample is less than 10. Skip anylizing in this cohort.")
    res <- list(KM_p_Infor = tibble())
  }

  return(res)
}
#' @title  复杂情况KM曲线v2版本
#' @inheritParams ComplexKM
#' @export
#' @param GroupManul *character*，分组信息所在列
#' @param legend KM曲线中图例位置
ComplexKM_v2 <- function(Input = NULL, surtime_unit = c(1, 12, 365), time_col = "time", type = "OS",
                         status_col = "status", score_col = "riskscore", BestCut = F, NormalCut = T, TertileCut = F,
                         QuartileCut = F, CutOffManual = NULL, GroupManul = NULL, legend = "top", SaveFile = F,
                         od = file.path(od, "out/"), w = 5, h = 5, Color_in_KM = NULL,risk.table = T) {
  library(tidyverse)
  library(survival)
  library(survminer)
  library(magrittr)
  library(crayon)
  library(ggpubr)

  if (is.null(Color_in_KM)) {
    Color_in_KM <- RColorBrewer::brewer.pal(9, "Set1")[c(2, 1, 3:9)]
  }

  input_check <- c(time_col, status_col, score_col, GroupManul) %>%
    is_in(colnames(Input)) %>%
    sum()

  if (input_check < 3) {
    warning(str_glue("{red('输入数据中，时间、状态、分组、得分某一列有误，检查输入数据或变量。')}"))
    return()
  }

  walk(colnames(Input), function(x) {
    # x <- 'sample'
    if ("time" == x & "time" != time_col) {
      Input <- Input %>%
        dplyr::rename(time_raw = "time")
    }
    if ("status" == x & "status" != status_col) {
      Input <- Input %>%
        dplyr::rename(status_raw = "status")
    }
    if ("Score" == x & isTRUE("Score" != score_col)) {
      Input <- Input %>%
        dplyr::rename(Score_raw = "Score")
    }
  })

  two_class_KM <- function(Data) {
    if (unique(Data$Group) %>%
      length() == 2) {
      if (all(unique(Data$Group) %in% c("Top", "Bottom"))) {
        legend_chr <- factor(c("Bottom", "Top"), levels = c("Top", "Bottom"))
        # legend_chr <- c('Bottom', 'Top')
      } else if (all(unique(Data$Group) %in% c("C1", "C2/C3/C4"))) {
        legend_chr <- c("C1", "C2/C3/C4")
      } else if (all(unique(Data$Group) %in% c("C4", "C1/C2/C3"))) {
        legend_chr <- c("C1/C2/C3", "C4")
      } else if (all(unique(Data$Group) %in% c("C1", "C4"))) {
        legend_chr <- c("C1", "C4")
      } else if (all(unique(Data$Group) %in% c("High", "Low"))) {
        legend_chr <- levels(Data$Group)
      } else {
        if (is.factor(Data$Group)) {
          legend_chr <- levels(Data$Group)
        } else {
          legend_chr <- unique(Data$Group) %>% sort()
        }
      }

      if (length(unique(Data$Group)) != 1) {
        coxtmp <- summary(coxph(Surv(time, status) ~ HR_group, data = Data))

        HR <- coxtmp$coefficients[2]
        logrank_pvalue <- coxtmp$sctest["pvalue"]
        lower_.95 <- coxtmp$conf.int[, "lower .95"]
        upper_.95 <- coxtmp$conf.int[, "upper .95"]
        C <- coxtmp$concordance[1]

        p_chara <- paste0(
          ifelse(logrank_pvalue < 0.001, "P < 0.001", paste0("P = ", round(logrank_pvalue, 3))), "\n", "HR = ", round(HR, 2), "\n95% CI = ",
          round(lower_.95, 2), " - ", round(upper_.95, 2)
          # "\nC-index = ",
          # round(C, 2)
        )

        if (surtime_unit == 12) {
          chara_xlab <- "Time (Months)"
        } else if (surtime_unit == 365) {
          chara_xlab <- "Time (Days)"
        } else if (surtime_unit == 1) {
          chara_xlab <- "Time (Years)"
        } else {
          chara_xlab <- "Time"
        }

        fit <- surv_fit(Surv(time, status) ~ Group, data = Data)
        KM <- ggsurvplot(fit,
          data = Data, surv.median.line = "hv",
          legend.title = legend.title_chr,
          legend.labs = legend_chr,
          legend = legend,
          palette = Color_in_KM,
          ggtheme = theme_survminer(),
          pval = p_chara,
          pval.size = 4.5,
          xlab = chara_xlab,
          tables.height = 0.28,
          risk.table = risk.table,
        )

        res <- list()

        p_auc_res <- tibble(KM_p = logrank_pvalue, HR = round(HR, 2))

        if (isTRUE(risk.table)) {
          p <- cowplot::plot_grid(
            KM$plot + theme(
              legend.background = element_blank(),
            ),
            KM$table + theme_cleantable() + suppressMessages(coord_cartesian(clip = "off")),
            ncol = 1,
            align = "v",
            rel_heights = c(0.78, 0.22)
          )
        }else {
           p <- KM$plot + theme(
              legend.background = element_blank(),
            )
        }

        

        res[[1]] <- p
        res[[2]] <- p_auc_res
      } else {
        res <- list()
      }
    }

    return(res)
  }

  more_class_KM <- function(Data) {
    if (unique(Data$Group) %>% length() != 2) {
      if (all(unique(Data$Group) %in% c("Top", "Mid", "Bottom"))) {
        # legend_chr <- c('Bottom', 'Mid', 'Top')
        legend_chr <- factor(c("Bottom", "Mid", "Top"), levels = c(
          "Top",
          "Mid", "Bottom"
        ))
      }

      if (all(unique(Data$Group) %in% c("C1", "C2", "C3", "C4"))) {
        legend_chr <- c("C1", "C2", "C3", "C4")
      } else {
        if (is.factor(Data$Group)) {
          legend_chr <- levels(Data$Group)
        } else {
          legend_chr <- unique(Data$Group) %>% sort()
        }
      }

      if (length(unique(Data$Group)) != 1) {
        if (surtime_unit == 12) {
          chara_xlab <- "Time (Months)"
        } else if (surtime_unit == 365) {
          chara_xlab <- "Time (Days)"
        } else if (surtime_unit == 1) {
          chara_xlab <- "Time (Years)"
        } else {
          chara_xlab <- "Time"
        }

        fit <- surv_fit(Surv(time, status) ~ Group, data = Data)
        KM <- ggsurvplot(fit,
          data = Data,
          surv.median.line = "hv",
          legend.title = legend.title_chr,
          palette = Color_in_KM,
          legend = legend,
          legend.labs = legend_chr,
          ggtheme = theme_survminer(),
          pval = T,
          pval.method = T,
          pval.size = 4.5,
          xlab = chara_xlab,
          tables.height = 0.28,
          risk.table = T
        )

        res <- list()

        p_auc_res <- tibble(surv_pvalue(fit, data = Data))
        p_auc_res <- p_auc_res %>%
          dplyr::select(-variable, -method, -pval.txt) %>%
          dplyr::rename(KM_p = pval)

        p <- cowplot::plot_grid(
          KM$plot + theme(
            legend.background = element_blank()
          ),
          KM$table + theme_cleantable() + suppressMessages(coord_cartesian(clip = "off")),
          ncol = 1, align = "v",
          rel_heights = c(0.78, 0.22)
        )

        # print(cowplot::plot_grid(p, res[[2]], rel_widths = c(0.95,
        # 1.05), scale = c(1, .97)))
        res[[1]] <- p
        res[[2]] <- p_auc_res
      } else {
        res <- list()
      }
    }

    return(res)
  }

  Input <- Input %>%
    dplyr::rename(time = all_of(time_col), status = all_of(status_col), Score = all_of(score_col)) %>%
    mutate(time = as.numeric(time), status = as.numeric(status)) %>%
    filter(time > 0) %>%
    filter(status != "NA" & status != "")

  if (!is.null(score_col)) {
    legend.title_chr <- score_col
    if (nrow(Input) > 5) {
      if (isTRUE(BestCut)) {
        sur.cut <- surv_cutpoint(
          data = Input, time = "time", event = "status",
          variables = "Score", minprop = 0.1
        )
        cut <- summary(sur.cut)$cutpoint

        Input_BestCut <- Input %>%
          mutate(HR_group = ifelse(Score > cut, 1, 0)) %>%
          mutate(Group = ifelse(Score > cut, "High", "Low")) %>%
          mutate(Group = factor(Group, levels = c("Low", "High")))

        BestCut_KM <- two_class_KM(Input_BestCut)
        names(BestCut_KM) <- c("KM_BestCut", "KM_BestCut_Infor")
        BestCut_KM[["BestCut_GroupInfor"]] <- Input_BestCut
      } else {
        BestCut_KM <- list()
      }

      if (NormalCut) {
        Input_normal <- Input %>%
          mutate(HR_group = ifelse(Score > median(Score), 1, 0)) %>%
          mutate(Group = ifelse(Score > median(Score), "High", "Low")) %>%
          mutate(Group = factor(Group, levels = c("Low", "High")))

        NormalCut_KM <- two_class_KM(Input_normal)
        names(NormalCut_KM) <- c("KM_NormalCut", "KM_NormalCut_Infor")
        NormalCut_KM[["NormalCut_GroupInfor"]] <- Input_normal
      } else {
        NormalCut_KM <- list()
      }

      if (TertileCut) {
        Input_TertileCut <- Input %>%
          mutate(Group = as.character(cut(Score,
            breaks = quantile(
              x = Score,
              probs = seq(0, 1, 1 / 3)
            ), labels = c("Bottom", "Mid", "Top"),
            include.lowest = TRUE
          ))) %>%
          mutate(Group = factor(Group, levels = c("Bottom", "Mid", "Top")))

        if (Input_TertileCut$Group %>%
          unique() %>%
          length() == 3) {
          Input_TertileCut_two <- Input_TertileCut %>%
            filter(Group %in% c("Top", "Bottom")) %>%
            mutate(HR_group = ifelse(Group == "Top", 1, 0))

          TertileCut_KM <- two_class_KM(Input_TertileCut_two)
          names(TertileCut_KM) <- c("KM_twoClass_in_TertileCut", "KM_twoClass_in_TertileCut_Infor")
          TertileCut_KM[["TertileCut_GroupInfor"]] <- Input_TertileCut

          TertileCut_Three_class_KM <- more_class_KM(Input_TertileCut)


          TertileCut_KM[["KM_threeClass_in_TertileCut"]] <- TertileCut_Three_class_KM[[1]]
          TertileCut_KM[["KM_threeClass_in_TertileCut_Infor"]] <- TertileCut_Three_class_KM[[2]]
        } else {
          TertileCut_KM <- list()
        }
      } else {
        TertileCut_KM <- list()
      }

      if (QuartileCut) {
        Input_QuartileCut <- Input %>%
          mutate(Group = as.character(cut(Score,
            breaks = quantile(
              x = Score,
              probs = seq(0, 1, 1 / 4)
            ), labels = c("C4", "C3", "C2", "C1"),
            include.lowest = TRUE
          ))) %>%
          mutate(Group = factor(Group, levels = c("C4", "C3", "C2", "C1")))

        if (unique(Input_QuartileCut$Group) %>%
          length() == 4) {
          Input_QuartileCut_C1C4 <- Input_QuartileCut %>%
            filter(Group %in% c("C1", "C4")) %>%
            mutate(HR_group = ifelse(Group == "C1", 1, 0)) %>%
            mutate(Group = factor(Group, levels = c("C4", "C1")))

          # rm(list = 'QuartileCut_KM')

          QuartileCut_KM <- two_class_KM(Input_QuartileCut_C1C4)
          names(QuartileCut_KM) <- c("KM_C1C4_in_QuartileCut", "KM_C1C4_in_QuartileCut_Infor")
          QuartileCut_KM[["QuartileCut_GroupInfor"]] <- Input_QuartileCut

          # names(QuartileCut_KM) 1 vs 234
          Input_QuartileCut_C1C234 <- Input_QuartileCut %>%
            mutate(HR_group = ifelse(Group == "C1", 1, 0)) %>%
            mutate(Group = case_when(Group %in% "C1" ~ "C1", Group %in%
              c("C2", "C3", "C4") ~ "C2/C3/C4")) %>%
            mutate(Group = factor(Group, levels = c("C2/C3/C4", "C1")))

          QuartileCut_KM_C1C234 <- two_class_KM(Input_QuartileCut_C1C234)
          QuartileCut_KM[["KM_C1C234_in_QuartileCut"]] <- QuartileCut_KM_C1C234[[1]]
          QuartileCut_KM[["KM_C1C234_in_QuartileCut_Infor"]] <- QuartileCut_KM_C1C234[[2]]

          # 123 vs 4
          Input_QuartileCut_C123C4 <- Input_QuartileCut %>%
            mutate(Group = case_when(Group %in% "C4" ~ "C4", Group %in%
              c("C1", "C2", "C3") ~ "C1/C2/C3")) %>%
            mutate(HR_group = ifelse(Group == "C1/C2/C3", 1, 0)) %>%
            mutate(Group = factor(Group, levels = c("C1/C2/C3", "C4")))

          QuartileCut_KM_C123C4 <- two_class_KM(Input_QuartileCut_C123C4)
          QuartileCut_KM[["KM_C123C4_in_QuartileCut"]] <- QuartileCut_KM_C123C4[[1]]
          QuartileCut_KM[["KM_C123C4_in_QuartileCut_Infor"]] <- QuartileCut_KM_C123C4[[2]]

          # 1 vs 2 vs 3 vs 4
          Input_QuartileCut_C1234 <- more_class_KM(Input_QuartileCut)
          QuartileCut_KM[["KM_C1234_in_QuartileCut"]] <- Input_QuartileCut_C1234[[1]]
          QuartileCut_KM[["KM_C1234_in_QuartileCut_Infor"]] <- Input_QuartileCut_C1234[[2]]
        } else {
          QuartileCut_KM <- list()
        }
      } else {
        QuartileCut_KM <- list()
      }

      if (!is.null(CutOffManual)) {
        Input_CutOffManual <- Input %>%
          mutate(HR_group = ifelse(Score > CutOffManual, 1, 0)) %>%
          mutate(Group = ifelse(Score > CutOffManual, "High", "Low"))

        CutOffManual_KM <- two_class_KM(Input_CutOffManual)
        names(CutOffManual_KM) <- c("KM_CutOffManual", "KM_CutOffManual_Infor")
        CutOffManual_KM[["CutOffManual_GroupInfor"]] <- Input_CutOffManual
      } else {
        CutOffManual_KM <- list()
      }

      res <- list(
        BestCut_KM, NormalCut_KM, TertileCut_KM, QuartileCut_KM,
        CutOffManual_KM
      )
      names(res) <- c(
        "BestCut_KM", "NormalCut_KM", "TertileCut_KM", "QuartileCut_KM",
        "CutOffManual_KM"
      )

      num_of_single_list <- map_int(names(res), ~ length(res[[.x]]))

      res_index <- which(num_of_single_list != 0)

      if (SaveFile) {
        if (!dir.exists(od)) {
          dir.create(od, recursive = T)
        }

        walk(res_index, function(x) {
          walk(names(res[[x]]), function(y) {
            single_file <- res[[x]][[y]]
            if (any(str_detect(class(single_file), "gg"))) {
              ggsave(
                plot = single_file, file = file.path(od, str_glue("Figure_{y}_KM_plot.pdf")),
                width = w, height = h
              )
            }
            if (any(str_detect(class(single_file), "data.frame"))) {
              write_tsv(x = single_file, file = file.path(od, str_glue("Table_{y}.tsv")))
            }
          })
        })
      }

      KM_p_Infor <- map_dfr(res_index, function(x) {
        p_infor <- map_dfr(names(res[[x]]), function(y) {
          single_file <- res[[x]][[y]]
          if (any(str_detect(class(single_file), "data.frame"))) {
            if (dim(single_file)[1] == 1) {
              single_file[["ClassType"]] <- y
              return(single_file)
            }
          }
        })
      })

      res <- res[res_index]
      res[["KM_p_Infor"]] <- KM_p_Infor
    } else {
      message(crayon::yellow("N.of sample is less than 5. Skip anylizing in this cohort."))
      res <- list(KM_p_Infor = tibble())
    }

    return(res)
  }

  if (!is.null(GroupManul)) {
    legend.title_chr <- GroupManul
    group_index <- which(str_detect(colnames(Input), GroupManul))
    colnames(Input)[group_index] <- "Group"
    km_group_num <- length(unique(Input[["Group"]]))

    if (km_group_num == 2) {
      if (all(unique(Input[["Group"]]) %in% c("Low", "High"))) {
        Input[["Group"]] <- factor(Input[["Group"]], levels = c("Low", "High"))
      }

      Input_GroupManul <- Input %>%
        mutate(HR_group = Group)

      two_GroupManul_KM <- two_class_KM(Input_GroupManul)
      names(two_GroupManul_KM) <- c("KM_GroupManul", "KM_2GroupManul_Infor")
      two_GroupManul_KM[["GroupManul_GroupInfor"]] <- Input_GroupManul
    } else {
      two_GroupManul_KM <- list()
    }

    if (km_group_num > 2) {
      Input_GroupManul <- Input %>%
        mutate(HR_group = Group)

      more_GroupManul_KM <- more_class_KM(Input_GroupManul)
      names(more_GroupManul_KM) <- c("KM_GroupManul", "KM_GroupManul_Infor")
      more_GroupManul_KM[["GroupManul_GroupInfor"]] <- Input_GroupManul
    } else {
      more_GroupManul_KM <- list()
    }

    if (km_group_num < 2) {
      message(str_glue("{crayon::bgRed('WARNING:')} 分组信息 {crayon::blue( )} 中类别小于2，不进行KM分析。"))
      res <- list(KM_p_Infor = tibble())
    }

    res_GroupManul <- list(two_GroupManul_KM, more_GroupManul_KM)
    names(res_GroupManul) <- c("two_GroupManul_KM", "more_GroupManul_KM")

    num_of_single_list <- map_int(names(res_GroupManul), ~ length(res_GroupManul[[.x]]))
    res_GroupManul_index <- which(num_of_single_list != 0)

    KM_p_Infor <- map_df(res_GroupManul_index, function(x) {
      # x <- 1
      p_infor <- map_df(names(res_GroupManul[[x]]), function(y) {
        # y <- 2
        single_file <- res_GroupManul[[x]][[y]]
        if (any(str_detect(class(single_file), "data.frame"))) {
          if (dim(single_file)[1] == 1) {
            single_file[["ClassType"]] <- y
            return(single_file)
          }
        }
      })
    })

    # res_GroupManul <- res_GroupManul[res_GroupManul_index]
    res_GroupManul[["KM_p_Infor"]] <- KM_p_Infor

    if (isTRUE(SaveFile)) {
      if (!dir.exists(od)) {
        dir.create(od, recursive = T)
      }

      walk(res_GroupManul_index, function(x) {
        walk(names(res_GroupManul[[x]]), function(y) {
          single_file <- res_GroupManul[[x]][[y]]
          if (any(str_detect(class(single_file), "gg"))) {
            ggsave(
              plot = single_file, file = file.path(od, str_glue("Figure_{y}_KM_plot.pdf")),
              width = w, height = h
            )
          }
          if (any(str_detect(class(single_file), "data.frame"))) {
            write_tsv(x = single_file, file = file.path(od, str_glue("Table_{y}.tsv")))
          }
        })
      })
    }

    return(res_GroupManul)
  }

  require(rlist)
  res_all <- rlist::list.append(res, res_GroupManul)

  class(res_all) <- c('list','complex_km')
  return(res_all)
}


if (F) {
    get_km <- function(x, ...) {
        UseMethod("get_km")
    }

    get_km.ckm <- function(x, ...) {
        stopifnot("complex_km" %in% class(x))
    }
}